/*=============================================================================
Copyright (c) 2010 Crytek Studios. All Rights Reserved.

Revision history:
* Created by Nicolas Schulz

=============================================================================*/

#ifndef STEREORENDERER_H
#define STEREORENDERER_H

#pragma once 

#include "IStereoRenderer.h"

class CD3D9Renderer;


enum StereoEye
{
	LEFT_EYE = 0,
	RIGHT_EYE = 1
};

#define STEREO_PS3_FRAMEPACKED_RESID  0x88







class CD3DStereoRenderer : public IStereoRenderer
{
public:
	CD3DStereoRenderer(CD3D9Renderer& renderer, StereoDevice device);
	virtual ~CD3DStereoRenderer();

	void InitDeviceBeforeD3D();
	void InitDeviceAfterD3D();
	void Shutdown();

	void CreateResources();
	void ReleaseResources();

	bool IsStereoEnabled() const { return m_device != STEREO_DEVICE_NONE && m_mode != STEREO_MODE_NO_STEREO; }
	bool IsPostStereoEnabled() const { return m_device != STEREO_DEVICE_NONE && m_mode == STEREO_MODE_POST_STEREO; }

	void PrepareStereo(StereoMode mode, StereoOutput output);

	StereoDevice GetStereoDevice() { return m_device; }
	StereoMode GetStereoMode() const { return m_mode; }
	StereoOutput GetStereoOutput() const { return m_output; }
	StereoEye GetCurrentEye() const { return m_curEye; }

	CTexture *GetLeftEye() { return m_pLeftTex; }
	CTexture *GetRightEye() { return m_pRightTex; }

	void Update();
	void ProcessScene(int sceneFlags);

	void CopyToStereo(int channel);
	void DisplayStereo();

	void BeginRenderingMRT(bool disableClear);
	void EndRenderingMRT(bool bResolve = true);

  void ResolveStereoBuffers();

	void BeginRenderingTo(StereoEye eye);
	void EndRenderingTo(StereoEye eye);

	void TakeScreenshot(const char path[]);

	float GetNearGeoShift() { return m_zeroParallaxPlaneDist; }
	float GetNearGeoScale() { return m_nearGeoScale; }
	float GetGammaAdjustment() { return m_gammaAdjustment; }

public:
	// IStereoRenderer Interface
	virtual StereoDevice GetDevice();
	virtual StereoDeviceState GetDeviceState();
	virtual bool GetStereoEnabled();
	virtual float GetStereoStrength();
	virtual float GetMaxSeparationScene(bool half=true);
	virtual float GetZeroParallaxPlaneDist();
	virtual void GetNVControlValues(bool &stereoEnabled, float &stereoStrength);

private:
	enum DriverType
	{
		DRIVER_UNKNOWN = 0,
		DRIVER_NV = 1,
		DRIVER_AMD = 2
	};
	
	CD3D9Renderer& m_renderer;

	StereoDevice m_device;
	StereoDeviceState m_deviceState;
	StereoMode m_mode;
	StereoOutput m_output;
	
	DriverType m_driver;

	CTexture *m_pLeftTex;
	CTexture *m_pRightTex;
	
	void  *m_nvStereoHandle;
	float m_nvStereoStrength;
	uint8 m_nvStereoActivated;












	StereoEye m_curEye;
	CCryNameR m_SourceSizeParamName;

	uint32 m_frontBufWidth, m_frontBufHeight;
	
	float m_stereoStrength;
	float m_zeroParallaxPlaneDist;
	float m_maxSeparationScene;
	float m_nearGeoScale;
	float m_gammaAdjustment;

	bool m_resourcesPatched;
	bool m_needClearLeft;
	bool m_needClearRight;

private:
	void SelectDefaultDevice();
	
	void CreateIntermediateBuffers();
	
	bool EnableStereo();
	void DisableStereo();
	void ChangeOutputFormat();
	void HandleNVControl();
	
	void PatchResources();
	void RestoreResources();

	void RenderScene(int sceneFlags);

	void SelectShaderTechnique();

	bool IsRenderThread() const;
	void CopyToStereoFromMainThread(int channel);

  void PushRenderTargets();
  void PopRenderTargets(bool bResolve);

	bool IsDriver( DriverType driver ) { return m_device == STEREO_DEVICE_DRIVER && m_driver == driver; }
};

#endif
